/**
 * This is a simple dataset implementation. It use an array to store the record. This is 
 * the reference implementation for dataset api. It shows how to implement a dataset.
 * In fact, how the dataset implemented depends on the datasource. But the datasouce can
 * also use or support this dataset.
 * 
 * @version 1.0
 * @since 1/5/2008
 * @author Jack
 */

dojo.provide("spaghetti.dataset.simpleDataset");

dojo.require("spaghetti.utility");
dojo.require("spaghetti.dataset.api");
dojo.provide("spaghetti.dataset.changeTracker");

dojo.declare("spaghetti.dataset.simpleMetaDataSupport", spaghetti.dataset.api.Metadata, {
	//	summary:
	//		This is the mixin for simple dataset to support metadata api. It use a metadata
	//		object to store the metadata. It resumes all the record are the same type.
	
	/*String[]*/
    getPropertyNames: function(/*Record || null*/record){
		return this.metadata.propertyNames;
    },
    
    /*Object*/
    getMetaData: function(/*String*/key){
        return this.metadata[key];
    },
    
    /*String*/
    getPropertyType: function(/*String*/property, /*Record || null*/ record){
		if(spaghetti.isNull(this.metadata.types))
			return null;
        return this.metadata.types[property];
    },
    
    /*Constraint*/
    getPropertyConstraint: function(/*String*/property, /*Record || null*/ record){
		//	TODO: Need think about this.
		if(spaghetti.isNull(this.metadata.constraints))
			return null;
		return this.metadata.constraints[property];
    }
});

dojo.declare("spaghetti.dataset.simpleDataSet", [spaghetti.dataset.ChangeTracker,
	spaghetti.dataset.simpleMetaDataSupport, spaghetti.dataset.api], {
	//	summary:
	//		This is the reference implementation for dataset api. It use an array to store
	//		the record. It resume all the record are the same type. The metadata for this 
	//		dataset is set by constructing this dataset.
	
	constructor : function(/*Object[]*/ data, /*Object*/ metadata){
		this.data = data;
		this.metadata = metadata;
		this.initTrack();
	},
	
	isRecord: function(/*Record*/record){
        // If this record isn't in this dataset. Return false.
		if(spaghetti.indexOf(record) == -1)
			return false;
		
		// Is the record implement the record api?
		return record.get && record.set && record.onChange;
    },
    
    /*Record*/
    getRecord: function(/*Number*/index){
		var record = this.data[index];
		
		// If didn't find the record, return null.
		if(spaghetti.isNull(record))
			return null;
		
		// If the record didn't implement the record api, extend it.
		if(!this.isRecord(record)){
			dojo.extend(record, spaghetti.dataset.api.Record);
		}
		return record;
    },
    
    addRecord: function(/*Object*/data, /*Number*/ index){
		var i = index;
		if(spaghetti.isNull(i))
			i = this.data.length;
		spaghetti.inert(this.data, data, index);
		// Fire the add event.
		this.onRecordAdd(data, i);
    },
    
    removeRecord: function(/*Record*/record){
		spaghetti.remove(this.data, record);
		// Fire the remove event
		this.onRecordRemove(record);
    },
    
    /*Object*/
    getProperty: function(/*Record*/record, /*String*/ property){
		return record[property];
    },
    
    setProperty: function(/*Record*/record, /*String*/ property, /*Object*/ value)/*Throws ValidationException*/{
		// Validate it first.
		var cons = this.getPropertyConstraint(property, record);
		if(cons && cons.getValidator())
			this.getPropertyConstraint(property, record).getValidator().validate(value);
		// Then set the value to the record.
		var oldValue = this.getProperty(record, property);
		record[property] = value;
		this.onRecordChange(record, property, oldValue, value);
    },
    
    /*Number*/
    indexOfRecord: function(/*Record*/record){
		return spaghetti.indexOf(this.data, record);
    },
    
    /*Number*/
    getRecordCount: function(){
		return this.data.length;
    },
    
    /*Cursor*/
    query: function(/*Object || null*/query){
        //	summary:
        //		Query in this dataset.  Mostly is the criteria of the record. Or constraints. 
        //	
        //	example:
        //	|	{ age : 26, name : "Jack"} or { begin : 10, end : 20, filter : funciton(index){ return index % 2; } } 
        //	|	or { index : 10 }. 
        //		The query return a cursor of the resultset. If the query is null, the resultset 
        //		is all the records in this dataset. Begin with index 0.
        
        spaghetti.notImplement("query");
    },
    
    /*Boolean*/
    isDirty: function(){
		return spaghetti.getPropertyNames(this).length != 0;
    }
});
